/*
       _             __
  ____(_)__ _______ / /____ ____
 / __/ (_-</ __(_-</ __/ -_) __/
/_/ /_/___/\__/___/\__/\__/_/

Napster client for RISC OS
Copyright (C) 2000 Robert Dimond

Portions are based on gnap by Ryan Dahl.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA

Bransley Cottage, Cleobury Mortimer, Kidderminster, WORCS. DY14 0BZ
England. robdimond@cwcom.net

*/

/*

OK, for some reason you have decided to read the source.  That is good.
Please understand, this is *not* an example of good program design.

*/

#include "runimage.h"


// starting number of 6 'head' icons in search window
#define SEARCH_HEADOFFSET 20
#define MINCOL 50

#define DEF_SRCHSIZE 1520

// max time before we return control back
#define POLLEVERY 20

int wmversion, finished = FALSE;
wimp_t taskhandle;



connect_level connected=notc;

int message_expire=-1;

char email[100]="";
char username[100]="", password[100]="";
char altserver_name[100]="";

char message_user[100]="";

int altserver_port=0;

int connection=0;

int listening_port;
int new_user=0;

//int colwidth[8]={696,940,1084,1204,1320,1496,1616};

int colwidth[8]={596,244,144,120,116,176,120};

char * motd[100];
int motd_line=0;

wimp_w win_connect;
wimp_window * win_connectb;
wimp_w win_info;
wimp_window * win_infob;
wimp_w win_mess;
wimp_window * win_messb;
wimp_w win_motd;
wimp_window * win_motdb;
wimp_w win_search;
wimp_window * win_searchb;
wimp_w win_searchres;
wimp_window * win_searchresb;
wimp_w win_sendmessage;
wimp_window * win_sendmessageb;

wimp_window * win_getb[C_DOWNLOADS];

osspriteop_area * sarea;

wimp_i icon_iconbar;

const char title[]="Riscster";

char * indirected_sp;
char * nextwd;

messagetrans_control_block mess_controlblock;
char * mbuffer;

wimp_menu * menu_ibar;
wimp_menu * menu_con;
wimp_menu * menu_com;
wimp_menu * menu_search;
wimp_menu * menu_complete;

int menu_search_lastres;
int menu_com_last;
wimp_w menu_con_last;

wimp_menu * menu_open;

int search_connection=0;
int search_c_br=0;
int search_c_lt=0;
int search_c_fr=0;
const char search_c[]="?>=<";

search_result * search_resblock=NULL;

search_result browsed_user;

search_type search_current_type = none;



int search_numres=0;
int search_currentres=0;

int last_get_update;

int topdrag_stat=0;
int topdrag_startx=0;

transfer downloads[C_DOWNLOADS];

incoming incon[C_INCOMING];

extern mp3file * mp3file_list;

void strcpy_nl(char * target, char * source);


void makeentry(wimp_menu_entry * ent, char * text, wimp_menu_flags flags,
                                      wimp_menu * sub,wimp_icon_flags more);
void standardmen(wimp_menu * menu);
wimp_window * loadwin(char * name);


int main(void)
{
 int evt;
 scanprogress scanblock;
 wimp_block block;
 os_t time;
 error(xwimp_initialise(400, title, NULL, &wmversion, &taskhandle));
 motd_init();
 get_init();
 ui_loadmessages();
 ui_loadsprites();
 ui_loadwindows();
 ui_setupmenus();
 ui_iconbaricon();
 napster_init_server();
 motd_addline("Welcome to Riscster 1.17");
 //lib_rescan_init(&scanblock);
 while(!finished)
 {
  /* Uncomment to scan !MP3's (for sharing) */
  error(xos_read_monotonic_time(&time));
  error(xwimp_poll_idle((connected||topdrag_stat)? 0 : wimp_MASK_NULL,
                        &block, time+POLLEVERY, NULL, &evt));
  switch(evt)
  {
   case wimp_NULL_REASON_CODE: mess_nullevent(&block);
   //if (scanblock.con!=-1) lib_rescan(&scanblock);
   break;
   case wimp_REDRAW_WINDOW_REQUEST: mess_redrawwindow(&block);
   break;
   case wimp_OPEN_WINDOW_REQUEST: mess_openwindow(&block);
   break;
   case wimp_CLOSE_WINDOW_REQUEST: mess_closewindow(&block);
   break;
   case wimp_MOUSE_CLICK: mess_mouseclick(&block);
   break;
   case wimp_USER_DRAG_BOX: mess_dragbox(&block);
   break;
   case wimp_KEY_PRESSED: mess_keypressed(&block);
   break;
   case wimp_MENU_SELECTION: mess_menuselect(&block);
   break;
   case wimp_USER_MESSAGE_RECORDED:
   case wimp_USER_MESSAGE: mess_usermessage(&block);
   break;
  }
 }
 ui_close();
 wimp_close_down(taskhandle);
 return(0);
}

void mess_keypressed(wimp_block * block)
{
 error(xwimp_process_key(block->key.c));
}

void mess_openwindow(wimp_block * block)
{
 wimp_open win;
 if (block->open.w==win_searchres)
 {
  win.w=win_search;
  win.visible.x0=block->open.visible.x0;
  win.visible.x1=block->open.visible.x1;
  win.visible.y1=block->open.visible.y1;
  win.visible.y0=block->open.visible.y0;
  win.xscroll=block->open.xscroll;
  win.yscroll=block->open.yscroll;
  win.next=block->open.next;
  error(xwimp_open_window(&win));
  block->open.next=win_search;
 }
 error(xwimp_open_window(&(block->open)));
}

void mess_closewindow(wimp_block * block)
{
 if (block->close.w==win_searchres) error(xwimp_close_window(win_search));
 error(xwimp_close_window(block->close.w));
}

void mess_usermessage(wimp_block * block)
{
  switch(block->message.action)
  {
    case 0: finished = TRUE;
    break;
    default:;
    break;
  }
}

void mess_nullevent(wimp_block * block)
{
 int i, time=0, time_beforepoll, action=0;
 time=os_read_monotonic_time();
 if (time>=message_expire)
 {
  error(xwimp_close_window(win_mess));
 }

 /* dirty hack no. 263 ;-) */
 do
 {
  action=napster_poll();
 } while((action)&&(os_read_monotonic_time()<(time+POLLEVERY)));

 if (time>(last_get_update+50))
 {
  for (i=0; i<C_DOWNLOADS; i++)
                   if (downloads[i].active==download) search_updatebar(i);
  last_get_update=time;
 }

 // redraw the top bar of the search window if we are dragging it
 if(topdrag_stat)
 {
  int disp;
  wimp_pointer pinfo;
  error(xwimp_get_pointer_info(&pinfo));
  disp=pinfo.pos.x-topdrag_startx;
  if(disp)
  {
   colwidth[topdrag_stat-1]+=disp;
   if(colwidth[topdrag_stat-1]<MINCOL) colwidth[topdrag_stat-1]=MINCOL;
   resize_searchhead(topdrag_stat-1);
   ui_force_topdraw(disp, topdrag_stat-1);
   topdrag_startx=pinfo.pos.x;
  }
 }
}

void mess_mouseclick(wimp_block * block)
{
 int i;
 if((block->pointer.i==icon_iconbar)&&(block->pointer.w==wimp_ICON_BAR))
 {
  switch(block->pointer.buttons)
  {
   case wimp_CLICK_MENU:
   error(xwimp_create_menu(menu_ibar,block->pointer.pos.x-64,96+(44*7)));
   menu_open=menu_ibar;
   break;
   case wimp_CLICK_SELECT:
   /* Open connect or search window depending on the connection state */
   switch(connected)
   {
    case notc:
    ui_openconnectwin();
    break;
    case loggedin:
    search_openwin();
    break;
    default: break;
   }
   break;
   case wimp_CLICK_ADJUST:
   {
    /* Open !MP3's dir */
    xos_cli("Filer_Run <Riscster$MusicDir>.^.!Run");
   }
  }
 }
 if(block->pointer.w==win_connect)
 {
  switch(block->pointer.i)
  {
   case CONNECTWIN_OKICON:  ui_connectok(); break;
   case CONNECTWIN_CONB:  ui_openconmenu(); break;
   case CONNECTWIN_NEWUSR: ui_newuserclick(); break;
   case CONNECTWIN_ALTS: ui_altserverclick(); break;
  }
 }
 else if(block->pointer.w==win_mess)
 {
  if (block->pointer.i==MESSAGEWIN_DISMISS)
  {
   error(xwimp_close_window(win_mess));
  }
 }
 else if(block->pointer.w==win_search)
 {
  switch(block->pointer.i)
  {
   case SEARCHWIN_BRC:
   case SEARCHWIN_LTC:
   case SEARCHWIN_FRC:
   ui_opencommenu(block->pointer.i);
   break;
   case SEARCHWIN_LTM: ui_opencon2menu();
   break;
   case SEARCHWIN_OK: search_ok();
   break;
  }
  if ((block->pointer.i>=SEARCH_HEADOFFSET)&&
      (block->pointer.i<=SEARCH_HEADOFFSET+6)) ui_search_drag(block);
 }
 else if(block->pointer.w==win_searchres)
 {
  search_click(block);
 }
 else if(block->pointer.w==win_sendmessage)
 {
  switch(block->pointer.i)
  {
   case MESSWIN_SEND: message_sendmessage(); break;
  }
 }
 for (i=0; i<C_DOWNLOADS; i++)
 {
  if (block->pointer.w==(wimp_w) downloads[i].whandle)
  {
   switch(block->pointer.i)
   {
    case GETWIN_OK: search_getok(i); break;
    case GETWIN_CANCEL: napster_download_end(i); break;
   }
  }
 }
}

void mess_menuselect(wimp_block * block)
{
 mp3file * i;
 wimp_pointer pointer;
 error(xwimp_get_pointer_info(&pointer));
 if (menu_open==menu_ibar)
 {
  switch(block->selection.items[0])
  {
   case 1: ui_openconnectwin(); break;
   case 2: napster_close(); break;
   case 3: search_openwin(); break;
   case 4:
   i=mp3file_list;
   while (i!=NULL)
   {
    if ((i->stat==incomplete)&&(i->menu==block->selection.items[1]))
    {
     search_complete(i);
    }
    i=i->next;
   }
   break;
   case 5: motd_openwin(); break;
   case 6: finished=TRUE; break;
  }
 } else
 if (menu_open==menu_con)
 {
  if (menu_con_last==win_connect)
  {
   connection=block->selection.items[0];
   ui_updatecond();
  }
  if (menu_con_last==win_search)
  {
   search_connection=block->selection.items[0];
   search_updatecond();
  }
 } else
 if (menu_open==menu_com)
 {
  switch(menu_com_last)
  {
   case SEARCHWIN_BRC: search_c_br=block->selection.items[0]; break;
   case SEARCHWIN_LTC: search_c_lt=block->selection.items[0]; break;
   case SEARCHWIN_FRC: search_c_fr=block->selection.items[0]; break;
  }
  search_updatecond();
 } else
 if (menu_open==menu_search)
 {
  switch(block->selection.items[0])
  {
   case 0: search_downloadclick(menu_search_lastres); break;
   case 1: search_browse(menu_search_lastres); break;
   case 2: message_send(menu_search_lastres); break;
  }
 }
 if (pointer.buttons==wimp_CLICK_ADJUST)
 {
  error(xwimp_create_menu(menu_open, 0, 0));
 }
}

void mess_redrawwindow(wimp_block * block)
{
 if (block->redraw.w==win_motd)
 {
  motd_redrawwin(block);
 } else
 if (block->redraw.w==win_searchres)
 {
  search_redrawwin(block);
 }
}

void ui_close(void)
{
 int i;
 napster_close();
 napster_end_server();
 error(xmessagetrans_close_file(&mess_controlblock));
 free(sarea);
 free(win_connectb);
 free(win_infob);
 free(win_messb);
 free(win_motdb);
 free(win_searchb);
 free(win_searchresb);
 free(menu_ibar);
 free(menu_con);
 free(menu_com);
 free(menu_search);
 free(mbuffer);
 search_new();
 for(i=0; i<C_DOWNLOADS; i++)
 {
  napster_download_end(i);
  free(win_getb[i]);
 }
 for(i=0; i<C_INCOMING; i++)
 {
  if(incon[i].active!=0)
  {
   xsocket_close(incon[i].socket);
  }
 }
 //lib_close();
}

void ui_openconnectwin(void)
{
 wimp_open open;
 wimp_pointer pointer;
 wimp_icon_state temp;
 int x, y;
 ui_loaddetails();
 temp.w=win_connect;
 temp.i=CONNECTWIN_USERNM;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, username);
 temp.i=CONNECTWIN_PASSWD;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, password);
 error(xwimp_get_pointer_info(&pointer));
 x=pointer.pos.x-64;
 y=128;
 open.visible.x0=x;
 open.visible.x1=x+500;
 open.visible.y0=y;
 open.visible.y1=y+380;
 open.w=win_connect;
 open.xscroll=0;
 open.yscroll=0;
 open.next=wimp_TOP;
 error(xwimp_open_window(&open));
 ui_updatecond();
}

void ui_iconbaricon(void)
{
 wimp_icon_create ib;
 ib.w=wimp_ICON_BAR_RIGHT;
 ib.icon.extent.x0=0;
 ib.icon.extent.y0=0;
 ib.icon.extent.x1=64;
 ib.icon.extent.y1=64;
 ib.icon.flags=wimp_ICON_SPRITE|wimp_ICON_HCENTRED|wimp_ICON_VCENTRED|
               (wimp_ICON_BUTTON_TYPE*wimp_BUTTON_CLICK);
 strcpy(ib.icon.data.sprite, "!riscster");
 error(xwimp_create_icon(&ib, &icon_iconbar));
}

void ui_loadsprites(void)
{
 FILE * file;
 int size=0;
 file = fopen("<Riscster$Dir>.Sprites", "rb");
 while(size++, fgetc(file)!=EOF);
 fclose(file);
 sarea=(osspriteop_area *) malloc(size+16);
 error(xosspriteop_clear_sprites(osspriteop_USER_AREA, sarea));
 error(xosspriteop_load_sprite_file(osspriteop_USER_AREA, sarea,
                                      "<Riscster$Dir>.Sprites"));

}

void ui_loadwindows(void)
{
 wimp_icon_state temp;
 int i;
 indirected_sp=malloc(ISIZE);
 nextwd=indirected_sp;
 error(xwimp_open_template("<Riscster$Dir>.Templates"));
 win_infob=loadwin("info");
 win_connectb=loadwin("connect");
 win_messb=loadwin("message");
 win_motdb=loadwin("motd");
 win_searchb=loadwin("search");
 win_searchresb=loadwin("searchres");
 win_sendmessageb=loadwin("privatemess");
 for (i=0; i<C_DOWNLOADS; i++)
 {
  win_getb[i]=loadwin("get");
  error(xwimp_create_window(win_getb[i], (wimp_w *) &downloads[i].whandle));
 }
 error(xwimp_close_template());
 win_infob->sprite_area=sarea;
 error(xwimp_create_window(win_infob, &win_info));
 error(xwimp_create_window(win_connectb, &win_connect));
 error(xwimp_create_window(win_messb, &win_mess));
 error(xwimp_create_window(win_motdb, &win_motd));
 error(xwimp_create_window(win_searchb, &win_search));
 error(xwimp_create_window(win_searchresb, &win_searchres));
 error(xwimp_create_window(win_sendmessageb, &win_sendmessage));
 temp.w=win_info;
 temp.i=INFOWIN_PURPOSE;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, PURPOSE);
 temp.w=win_info;
 temp.i=INFOWIN_AUTHOR;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, AUTHOR);
 temp.w=win_info;
 temp.i=INFOWIN_VERSION;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, VERSION);
}

wimp_window * loadwin(char * name)
{
 wimp_window * win;
 int used, dused;
 error(xwimp_load_template(0, nextwd, indirected_sp+(ISIZE), 0,
                           name, 0, &used, &dused, NULL));
 win = (wimp_window *) malloc(used);
 error(xwimp_load_template(win, nextwd, indirected_sp+(ISIZE), 0,
                           name, 0, NULL, &dused, NULL));
 nextwd=(char *) dused;
 return(win);
}

void ui_loadmessages(void)
{
 FILE * file;
 int size=0;
 file = fopen("<Riscster$Dir>.Messages", "rb");
 while(size++, fgetc(file)!=EOF);
 mbuffer = malloc(size+16);
 error(xmessagetrans_open_file(&mess_controlblock, "<Riscster$Dir>.Messages",
                               mbuffer));
}

void ui_setupmenus(void)
{
 wimp_menu_entry * ent;
 char buffer[20];
 char str[20];
 char * out;
 size_t size;
 int  i;
 size = sizeof(wimp_menu)+(sizeof(wimp_menu_entry)*8);
 menu_ibar=malloc(size);
 error(xmessagetrans_lookup(&mess_controlblock, "IBMENUT", buffer, 20,
                            NULL, NULL, NULL, NULL, &out, NULL));
 strcpy(menu_ibar->title_data.text, out);
 standardmen(menu_ibar);
 ent=(wimp_menu_entry *) &menu_ibar->entries;
 makeentry(ent++, "IBMENU1",0,(wimp_menu *)win_info,0);                       makeentry(ent++, "IBMENU2",0,NULL,0);
 makeentry(ent++, "IBMENU3",0,NULL,wimp_ICON_SHADED);
 makeentry(ent++, "IBMENU4",0,NULL,wimp_ICON_SHADED);
 makeentry(ent++, "IBMENU5",0,NULL,wimp_ICON_SHADED);
 makeentry(ent++, "IBMENU6",0,NULL,0);
 makeentry(ent++, "IBMENU7",wimp_MENU_LAST, NULL,0);
 size = sizeof(wimp_menu)+(sizeof(wimp_menu_entry)*12);
 menu_con=malloc(size);
 error(xmessagetrans_lookup(&mess_controlblock, "CONT", buffer, 20,
                            NULL, NULL, NULL, NULL, &out, NULL));
 strcpy(menu_con->title_data.text, out);
 standardmen(menu_con);
 ent=(wimp_menu_entry *) &menu_con->entries;
 for (i=0; i<10; i++)
 {
  sprintf(str, "CON%d", i);

  makeentry(ent++, str, 0, NULL, 0);

 }

 makeentry(ent++,"CON10", wimp_MENU_LAST, NULL, 0);

 size = sizeof(wimp_menu)+(sizeof(wimp_menu_entry)*5);
 menu_com=malloc(size);
 error(xmessagetrans_lookup(&mess_controlblock, "COMT", buffer, 20,
                            NULL, NULL, NULL, NULL, &out, NULL));
 strcpy(menu_com->title_data.text, out);
 standardmen(menu_com);
 ent=(wimp_menu_entry *) &menu_com->entries;
 for (i=0; i<3; i++)
 {
  sprintf(str, "COM%d", i);
  makeentry(ent++, str, 0, NULL, 0);

 }

 makeentry(ent++, "COM3", wimp_MENU_LAST, NULL, 0);
 size = sizeof(wimp_menu)+(sizeof(wimp_menu_entry)*5);
 menu_search=malloc(size);
 error(xmessagetrans_lookup(&mess_controlblock, "SMENUT", buffer, 20,
                            NULL, NULL, NULL, NULL, &out, NULL));
 strcpy(menu_search->title_data.text, out);
 standardmen(menu_search);
 ent=(wimp_menu_entry *) &menu_search->entries;

 makeentry(ent++, "SMENU1",0,NULL,0);
 makeentry(ent++, "SMENU2",0,NULL,0);
 makeentry(ent++, "SMENU3",0,NULL,0);
 makeentry(ent++, "SMENU4",wimp_MENU_LAST, NULL, wimp_ICON_SHADED);

}

/*

YUK!  YUK! URRGGGGHH!

I can't believe that I did this!!!

wimp_menu_entry * makeentry(char * text, wimp_menu_flags flags, wimp_menu * sub, wimp_icon_flags more)
{
 char buffer[20];
 wimp_menu_entry temp;
 char * out;
 error(xmessagetrans_lookup(&mess_controlblock, text, buffer, 20,
                            NULL, NULL, NULL, NULL, &out, NULL));
 temp.menu_flags=flags;
 temp.sub_menu=sub;
 temp.icon_flags=0x7000021|more;
 strcpy(temp.data.text, out);
 return(&temp);
}
*/

void makeentry(wimp_menu_entry * ent, char * text, wimp_menu_flags flags,
                                     wimp_menu * sub, wimp_icon_flags more)
{
 char buffer[20];
 char * out;
 error(xmessagetrans_lookup(&mess_controlblock, text, buffer, 20,
                            NULL, NULL, NULL, NULL, &out, NULL));
 ent->menu_flags=flags;
 ent->sub_menu=sub;
 ent->icon_flags=0x7000021|more;
 strcpy(ent->data.text, out);
}

void ui_connectok(void)
{
 wimp_icon_state temp;
 int err=0;
 temp.w=win_connect;
 temp.i=CONNECTWIN_USERNM;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(username, temp.icon.data.indirected_text.text);
 temp.i=CONNECTWIN_PASSWD;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(password, temp.icon.data.indirected_text.text);
 temp.i=CONNECTWIN_EMAIL;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(email, temp.icon.data.indirected_text.text);
 temp.i=CONNECTWIN_NEWUSR;
 error(xwimp_get_icon_state(&temp));
 if (temp.icon.flags&wimp_ICON_SELECTED) new_user=1;
 temp.i=CONNECTWIN_ALTST;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(altserver_name, temp.icon.data.indirected_text.text);

 if (strlen(username)<1)
 {
  ui_messalert("ERRUSERN");
  err=1;
 }
 if (strlen(password)<1)
 {
  ui_messalert("ERRPASSW");
  err=1;
 }
 if ((strlen(email)<1)&&(new_user==1))
 {
  ui_messalert("ERREMAIL");
  err=1;
 }
 if (err) return;
 temp.i=CONNECTWIN_REMD;
 error(xwimp_get_icon_state(&temp));
 if (temp.icon.flags&wimp_ICON_SELECTED) ui_storedetails();

 temp.i=CONNECTWIN_ALTS;
 error(xwimp_get_icon_state(&temp));
 motd_addline("Trying to resolve server...");
 if (temp.icon.flags&wimp_ICON_SELECTED)
 {
  char * port;
  port = strchr(altserver_name, ':');
  if (port==NULL)
  {
   ui_messalert("ERRPORT");
   return;
  }
  *port='\0';
  altserver_port=atoi(port+sizeof(char));
  napster_resolve_alt();
 }
 else
 {
  napster_resolve_redir();
 }
 error(xwimp_close_window(win_connect));
}

void ui_newuserclick(void)
{
 wimp_icon_state newusr;
 newusr.w=win_connect;
 newusr.i=CONNECTWIN_NEWUSR;
 error(xwimp_get_icon_state(&newusr));
 if (newusr.icon.flags&wimp_ICON_SELECTED)
 {
  error(xwimp_set_icon_state(win_connect,
                                CONNECTWIN_EMAIL, 0, wimp_ICON_SHADED));
 }
 else
 {
  error(xwimp_set_icon_state(win_connect,
                 CONNECTWIN_EMAIL, wimp_ICON_SHADED, wimp_ICON_SHADED));
 }
}

void ui_altserverclick(void)
{
 wimp_icon_state alts;
 alts.w=win_connect;
 alts.i=CONNECTWIN_ALTS;
 error(xwimp_get_icon_state(&alts));
 if (alts.icon.flags&wimp_ICON_SELECTED)
 {
  error(xwimp_set_icon_state(win_connect,
                                CONNECTWIN_ALTST, 0, wimp_ICON_SHADED));
 }
 else
 {
  error(xwimp_set_icon_state(win_connect,
                 CONNECTWIN_ALTST, wimp_ICON_SHADED, wimp_ICON_SHADED));
 }
}

void ui_messalert(char * token)
{
 char buffer[100];
 char * out;
 error(xmessagetrans_lookup(&mess_controlblock, token, buffer, 100,
                            NULL, NULL, NULL, NULL, &out, NULL));
 ui_alert(out);
}

void ui_alert(char * text)
{
 wimp_open open;
 wimp_icon_state temp;
 int sx, sy, xeig, yeig, swidth, sheight, xwa, ywa;
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XEIG_FACTOR, &xeig,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YEIG_FACTOR, &yeig,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XWIND_LIMIT, &sx,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YWIND_LIMIT, &sy,
                                                                        NULL));
 swidth=sx<<xeig;
 sheight=sy<<yeig;
 xwa=win_messb->extent.x1-win_messb->extent.x0;
 ywa=win_messb->extent.y1-win_messb->extent.y0;
 open.w=win_mess;
 open.visible.x0=(swidth/2)-(xwa/2);
 open.visible.y0=(sheight/2)-(ywa/2);
 open.visible.x1=xwa+open.visible.x0;
 open.visible.y1=ywa+open.visible.y0;
 open.xscroll=0; open.yscroll=0;
 open.next=wimp_TOP;
 temp.w=win_mess;
 temp.i=MESSAGEWIN_MESSAGE;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, text);
 error(xwimp_set_icon_state(win_mess, MESSAGEWIN_MESSAGE, 0,0));
 error(xwimp_open_window(&open));
 message_expire=os_read_monotonic_time()+MESSAGE_DELAY;
}

void standardmen(wimp_menu * menu)
{
 menu->title_fg=7;
 menu->title_bg=2;
 menu->work_fg=7;
 menu->work_bg=0;
 menu->height=44;
 menu->gap=0;
}


int error(os_error * err)
{
 if (err!=NULL)
 {
  wimp_report_error(err, wimp_ERROR_BOX_OK_ICON|wimp_ERROR_BOX_CATEGORY_ERROR,
                    title);
  return(1);
 }
 return(0);
}

void connectedchange(int new)
{
 wimp_menu_entry * ent;
 connected=(connect_level) new;
 ent = (wimp_menu_entry *) &menu_ibar->entries;
 switch(connected)
 {
  case notc:
  (ent+1)->icon_flags=0x7000021;
  (ent+2)->icon_flags=0x7000021|wimp_ICON_SHADED;
  (ent+3)->icon_flags=0x7000021|wimp_ICON_SHADED;
  (ent+4)->icon_flags=0x7000021|wimp_ICON_SHADED;
  break;
  case nap_res:
  case tc_redir:
  case get_redir:
  case tc_server:
  case try_login:
  (ent+1)->icon_flags=0x7000021|wimp_ICON_SHADED;
  (ent+2)->icon_flags=0x7000021;
  (ent+3)->icon_flags=0x7000021|wimp_ICON_SHADED;
  (ent+4)->icon_flags=0x7000021|wimp_ICON_SHADED;
  break;
  case loggedin:
  (ent+1)->icon_flags=0x7000021|wimp_ICON_SHADED;
  (ent+2)->icon_flags=0x7000021;
  (ent+3)->icon_flags=0x7000021;
  (ent+4)->icon_flags=0x7000021|wimp_ICON_SHADED;
  break;
 }
 if (connected!=loggedin)
 {
  error(xwimp_close_window(win_searchres));
  error(xwimp_close_window(win_search));
 }
}


void ui_openconmenu(void)
{
 int x, y;
 wimp_icon_state conicon;
 wimp_window_state wind;
 conicon.w=win_connect;
 conicon.i=CONNECTWIN_CONB;
 error(xwimp_get_icon_state(&conicon));
 wind.w=win_connect;
 error(xwimp_get_window_state(&wind));
 x=wind.visible.x0+conicon.icon.extent.x1;
 y=wind.visible.y1+conicon.icon.extent.y1;
 error(xwimp_create_menu(menu_con, x, y));
 menu_open=menu_con;
 menu_con_last=win_connect;
}

void ui_opencon2menu(void)
{
 int x, y;
 wimp_icon_state conicon;
 wimp_window_state wind;
 conicon.w=win_search;
 conicon.i=SEARCHWIN_LTM;
 error(xwimp_get_icon_state(&conicon));
 wind.w=win_search;
 error(xwimp_get_window_state(&wind));
 x=wind.visible.x0-wind.xscroll+conicon.icon.extent.x1;
 y=wind.visible.y1-wind.yscroll+conicon.icon.extent.y1;
 error(xwimp_create_menu(menu_con, x, y));
 menu_open=menu_con;
 menu_con_last=win_search;
}

void ui_opencommenu(wimp_i icon)
{
 int x, y;
 wimp_icon_state comicon;
 wimp_window_state wind;
 comicon.w=win_search;
 comicon.i=icon;
 error(xwimp_get_icon_state(&comicon));
 wind.w=win_search;
 error(xwimp_get_window_state(&wind));
 x=wind.visible.x0-wind.xscroll+comicon.icon.extent.x1;
 y=wind.visible.y1-wind.yscroll+comicon.icon.extent.y1;
 error(xwimp_create_menu(menu_com, x, y));
 menu_open=menu_com;
 menu_com_last=(int) icon;
}

void ui_updatecond()
{
 wimp_icon_state temp;
 char buffer[100];
 char * out;
 char token[20];
 sprintf(token, "CON%d", connection);
 error(xmessagetrans_lookup(&mess_controlblock, token, buffer, 100,
                            NULL, NULL, NULL, NULL, &out, NULL));
 temp.w=win_connect;
 temp.i=CONNECTWIN_COND;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, out);
 error(xwimp_set_icon_state(win_connect, CONNECTWIN_COND, 0,0));
}

void motd_openwin(void)
{
 wimp_open open;
 int sx, sy, xeig, yeig, swidth, sheight, xwa, ywa;
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XEIG_FACTOR, &xeig,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YEIG_FACTOR, &yeig,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XWIND_LIMIT, &sx,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YWIND_LIMIT, &sy,
                                                                        NULL));
 swidth=sx<<xeig;
 sheight=sy<<yeig;
 xwa=win_motdb->extent.x1-win_motdb->extent.x0;
 ywa=win_motdb->extent.y1-win_motdb->extent.y0;
 open.w=win_motd;
 open.visible.x0=(swidth/2)-(xwa/2);
 open.visible.y0=(sheight/2)-(ywa/2);
 open.visible.x1=xwa+open.visible.x0;
 open.visible.y1=ywa+open.visible.y0;
 open.xscroll=0; open.yscroll=0;
 open.next=wimp_TOP;
 error(xwimp_open_window(&open));
}

void motd_redrawwin(wimp_block * block)
{
 wimp_draw area;
 wimp_window_state wind;
 int more=0;
 int xorigin, yorigin;
 wind.w=block->redraw.w;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll;
 area = block->redraw;
 error(xwimp_redraw_window(&area, &more));
 if (more) motd_drawblock(&area, more, xorigin, yorigin);
}

void motd_drawblock(wimp_draw * area, int more, int xorigin, int yorigin)
{
  int startline, endline, line;
  startline=((area->clip.y1-yorigin)/-50);
  endline=((area->clip.y0-yorigin)/-50)+1;
  if (startline>motd_line) startline=motd_line;
  if (startline<0) startline=0;
  if (endline>motd_line) endline=motd_line;
  if (endline<0) endline=0;
  for (line=startline; line<endline; line++)
  {
   if (motd[line]!=NULL)
   {
    error(xwimptextop_set_colour(os_COLOUR_BLACK, os_COLOUR_VERY_LIGHT_GREY));
    error(xwimptextop_paint(wimptextop_GIVEN_BASELINE, motd[line],
                                xorigin+20, yorigin-((line+1)*50)));
   }
  }
  error(xwimp_get_rectangle(area, &more));
  if (more) motd_drawblock(area, more, xorigin, yorigin);
}

void motd_addline(char * text)
{
 char * split;
 char * scan;
 char temp;
 int nosplit=1;
 scan=text;
 while(nosplit)
 {
  error(xfont_scan_string(wimpreadsysinfo_font(NULL),
                          scan,
                          font_GIVEN_FONT|font_RETURN_SPLIT_COUNT,
                          (win_motdb->extent.x1-40)*400,
                          1024*400,
                          NULL,
                          NULL,
                          strlen(scan),
                          &split,
                          NULL,
                          NULL,
                          &nosplit));

  temp=*split;
  *split='\0';
  if(strlen(scan)) motd_addline_actual(scan);
  *split=temp;

  if(nosplit)
  {
   scan=split;
  }
 }
}

void motd_addline_actual(char * text)
{
 int xorigin, yorigin, more;
 os_box box;
 wimp_window_state wind;
 wimp_draw red;
 wind.w=win_motd;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll;
 if (motd_line>=100) motd_reset();
 motd[motd_line] = malloc((strlen(text)+1)*sizeof(char));
 strcpy(motd[motd_line], text);
 motd_line++;
 if (wind.visible.y1-wind.visible.y0<(motd_line+2)*50)
 {
  box.x0=win_motdb->extent.x0;
  box.x1=win_motdb->extent.x1;
  box.y1=0;
  win_motdb->extent.y1=0;
  box.y0=-((motd_line+2)*50);
  win_motdb->extent.y0=box.y0;
  error(xwimp_set_extent(win_motd, &box));
 }
 red.w=win_motd;
 red.box.x0=win_motdb->extent.x0;
 red.box.x1=win_motdb->extent.x1;
 red.box.y0=-((motd_line+1)*50);
 red.box.y1=-((motd_line-1)*50);
 error(xwimp_update_window(&red, &more));
 if (more) motd_drawblock(&red, more, xorigin, yorigin);
}

void motd_reset(void)
{
 int i;
 motd_line=0;
 for (i=0; i<100; i++)
 {
  if (motd[i]!=NULL) free(motd[i]);
  motd[i]=NULL;
 }
}

void motd_init(void)
{
 int i;
 for (i=0; i<100; i++)
 {
  motd[i]=NULL;
 }
}

void search_openwin(void)
{
 wimp_open open, open2;
 int sx, sy, xeig, yeig, swidth, sheight, xwa, ywa;
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XEIG_FACTOR, &xeig,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YEIG_FACTOR, &yeig,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XWIND_LIMIT, &sx,
                                                                        NULL));
 error(xos_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YWIND_LIMIT, &sy,
                                                                        NULL));
 swidth=sx<<xeig;
 sheight=sy<<yeig;
 xwa=win_searchresb->extent.x1-win_searchresb->extent.x0;
 ywa=win_searchresb->extent.y1-win_searchresb->extent.y0;
 open.w=win_searchres;
 open.visible.x0=(swidth/2)-(xwa/2);
 open.visible.y0=(sheight/2)-(ywa/2);
 open.visible.x1=xwa+open.visible.x0;
 open.visible.y1=ywa+open.visible.y0;
 open.xscroll=0; open.yscroll=0;
 open.next=wimp_TOP;
 error(xwimp_open_window(&open));
 open2.w=win_search;
 open2.visible.x0=open.visible.x0;
 open2.visible.x1=open.visible.x1;
 open2.visible.y0=open.visible.y0;
 open2.visible.y1=open.visible.y1;
 open2.xscroll=0;
 open2.yscroll=0;
 open2.next=open.next;
 error(xwimp_open_window(&open2));
 search_updatecond();
 search_ungrey();

}

void search_updatecond()
{
 wimp_icon_state temp;
 char buffer[100];
 char * out;
 char token[20];
 sprintf(token, "CON%d", search_connection);
 error(xmessagetrans_lookup(&mess_controlblock, token, buffer, 100,
                            NULL, NULL, NULL, NULL, &out, NULL));
 temp.w=win_search;
 temp.i=SEARCHWIN_LTI;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, out);
 error(xwimp_set_icon_state(win_search, SEARCHWIN_LTI, 0,0));

 temp.w=win_search;
 temp.i=SEARCHWIN_BRD;
 error(xwimp_get_icon_state(&temp));
 temp.icon.data.indirected_text.text[0]=search_c[search_c_br];
 temp.icon.data.indirected_text.text[1]='\0';
 error(xwimp_set_icon_state(win_search, SEARCHWIN_BRD, 0,0));

 temp.w=win_search;
 temp.i=SEARCHWIN_LTD;
 error(xwimp_get_icon_state(&temp));
 temp.icon.data.indirected_text.text[0]=search_c[search_c_lt];
 temp.icon.data.indirected_text.text[1]='\0';
 error(xwimp_set_icon_state(win_search, SEARCHWIN_LTD, 0,0));

 temp.w=win_search;
 temp.i=SEARCHWIN_FRD;
 error(xwimp_get_icon_state(&temp));
 temp.icon.data.indirected_text.text[0]=search_c[search_c_fr];
 temp.icon.data.indirected_text.text[1]='\0';
 error(xwimp_set_icon_state(win_search, SEARCHWIN_FRD, 0,0));

}

/*void search_ok()
{
 char artist[50], title[50], bitrate[5], maxres[5], freq[10];
 char out[500]; char add[50];
 search_result * tb;
 char * comp[4];
 char atleast[]="AT LEAST";
 char atbest[]="AT BEST";
 char equalto[]="EQUAL TO";
 search_result * item;
 wimp_icon_state temp;
 comp[1]=atleast; comp[3]=atbest; comp[2]=equalto;
 temp.w=win_search;
 temp.i=SEARCHWIN_ARTIST;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(artist, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_TRACK;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(title, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_MAXRES;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(maxres, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_BRI;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(bitrate, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_FRI;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(freq, temp.icon.data.indirected_text.text);
 sprintf(out,
 "FILENAME CONTAINS \"%s\" MAX_RESULTS %s FILENAME CONTAINS \"%s\" ",
 artist, maxres, title);
 if (search_c_br)
 {
  sprintf(add, "BITRATE \"%s\" \"%s\" ", comp[search_c_br], bitrate);
  strcat(out, add);
 }
 if (search_c_fr)
 {
  sprintf(add, "FREQ \"%s\" \"%s\" ", comp[search_c_fr], freq);
  strcat(out, add);
 }
 if (search_c_lt)
 {
  sprintf(add, "LINESPEED \"%s\" %d ", comp[search_c_lt], search_connection);
  strcat(out, add);
 }
 if (!strcmp(maxres, "")) strcpy(maxres, "50");
 search_new();
 napster_send(out, 200, strlen(out));
 error(xwimp_set_icon_state(win_search, SEARCHWIN_OK,
                   wimp_ICON_SHADED, wimp_ICON_SHADED));
}*/

void search_ok()
{
 char artist[50], title[50], bitrate[5], maxres[5], freq[10];
 char out[500]=""; char add[50]="";
 char * comp[4];
 char atleast[]="AT LEAST";
 char atbest[]="AT BEST";
 char equalto[]="EQUAL TO";
 wimp_icon_state temp;
 comp[1]=atleast; comp[3]=atbest; comp[2]=equalto;
 temp.w=win_search;
 temp.i=SEARCHWIN_ARTIST;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(artist, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_TRACK;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(title, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_MAXRES;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(maxres, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_BRI;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(bitrate, temp.icon.data.indirected_text.text);
 temp.i=SEARCHWIN_FRI;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(freq, temp.icon.data.indirected_text.text);

 if((!strlen(artist))&&(!strlen(title)))
 {
  ui_messalert("ERRNTNA");
  return;
 }
 if(strlen(artist))
 {
  sprintf(add, "FILENAME CONTAINS \"%s\" ", artist);
  strcat(out, add);
 }
 if(strlen(maxres))
 {
  sprintf(add, "MAX_RESULTS %s ", maxres);
  strcat(out, add);
 }
 if(strlen(title))
 {
  sprintf(add, "FILENAME CONTAINS \"%s\" ", title);
  strcat(out, add);
 }
 if (search_c_br)
 {
  sprintf(add, "BITRATE \"%s\" \"%s\" ", comp[search_c_br], bitrate);
  strcat(out, add);
 }
 if (search_c_fr)
 {
  sprintf(add, "FREQ \"%s\" \"%s\" ", comp[search_c_fr], freq);
  strcat(out, add);
 }
 if (search_c_lt)
 {
  sprintf(add, "LINESPEED \"%s\" %d ", comp[search_c_lt], search_connection);
  strcat(out, add);
 }
 search_changetype(search);
 search_new();
 /*napster_mess_searchresponse("\"I like cheddar cheese oh yeah - Ricky Dreamer and the Puzzlers\" 000000000 12823 128 44100 1202 Ned 121212 2");*/
 napster_send(out, 200, strlen(out));
}

void search_new()
{
 search_result * i, * oi;
 i=search_resblock;
 while (i!=NULL)
 {
  oi=i;
  i=i->next;
  free(oi);
 }
 search_resblock=NULL;
 search_numres=0;
 search_update_wholewin();
}

void search_ungrey()
{
 error(xwimp_set_icon_state(win_search, SEARCHWIN_OK,
        0, wimp_ICON_SHADED));
}

void search_update(search_result * result)
{
 search_result * i;
 int no=0, xorigin, yorigin;
 wimp_draw red;
 wimp_window_state wind;
 //wimp_open openblock;
 wimp_window_state stateblock;
 os_box box;
 int more=0;
 /* Add new result to linked list in search_resblock */
 i=search_resblock;
 if(i==NULL)
 {
  search_resblock=result;
 }
 else
 {
  while (i->next!=NULL)
  {
   i=i->next;
   no++;
  }
  i->next=result;
 }
 search_numres++;
 /* Update search window (resize and redraw) */
 wind.w=win_searchres;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll-250;
 box.y1=win_searchresb->extent.y1;
 box.x0=win_searchresb->extent.x0;
 box.x1=win_searchresb->extent.x1;
 box.y0=-50*(no+1)-250;
 win_searchresb->extent.y0=box.y0;
 error(xwimp_set_extent(win_searchres, &box));

 /*  No need for this crummy 'fix' anymore
 openblock.visible.y0=wind.visible.y0;
 openblock.visible.y1=wind.visible.y1;
 if ((wind.visible.y1-wind.visible.y0)>(50*(no+1)-250))
 {
  openblock.visible.y0=openblock.visible.y1-(50*(no+1)-250);
 }
 openblock.w=win_searchres;
 openblock.visible.x0=wind.visible.x0;
 openblock.visible.x1=wind.visible.x1;
 openblock.yscroll=wind.yscroll;
 openblock.xscroll=wind.xscroll;
 openblock.next=wind.next;
 error(xwimp_open_window(&openblock));*/
 red.w=win_searchres;
 red.box.x0=win_searchresb->extent.x0;
 red.box.x1=win_searchresb->extent.x1;
 red.box.y0=-50*(no+1)-250;
 red.box.y1=-50*(no)-250;
 error(xwimp_update_window(&red, &more));
 if (more) search_drawblock(&red, more, xorigin, yorigin);
}

void search_finish()
{
 os_box box;
 wimp_window_state wind;

 int xorigin, yorigin;
 wind.w=win_searchres;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll-250;

 /*search_numres=0;
 i=search_resblock;
 while (i!=NULL)
 {
  i=i->next;
  search_numres++;
 }*/

 box.y1=win_searchresb->extent.y1;
 box.x0=win_searchresb->extent.x0;
 box.x1=win_searchresb->extent.x1;
 box.y0=-50*(search_numres+1)-250;
 error(xwimp_set_extent(win_searchres, &box));
 search_update_wholewin();
 search_changetype(none);
}

void search_update_wholewin(void)
{

 int more=0;
 wimp_draw red;
 wimp_window_state wind;
 int xorigin, yorigin;

 wind.w=win_searchres;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll-250;

 red.w=win_searchres;
 red.box.x0=win_searchresb->extent.x0;
 red.box.x1=win_searchresb->extent.x1;
 red.box.y0=-50*(search_numres+1)-250;
 win_searchresb->extent.y0=red.box.y0;
 red.box.y1=win_searchresb->extent.y1;
 error(xwimp_update_window(&red, &more));
 if (more) search_drawblock(&red, more, xorigin, yorigin);
}

void search_drawblock(wimp_draw * area, int more, int xorigin, int yorigin)
{
 int startline, endline, line;
 char numconv[10];
 char * out;
 char buffer[100], token[6];
 char blank[]="";
 search_result * sr;
 startline=((area->clip.y1-yorigin)/-50);
 endline=((area->clip.y0-yorigin)/-50)+1;
 if (startline>search_numres) startline=search_numres;
 if (startline<0) startline=0;
 if (endline>search_numres) endline=search_numres;
 if (endline<0) endline=0;
 error(xwimp_set_colour(wimp_COLOUR_WHITE));
 error(xos_plot(4, area->clip.x0, area->clip.y0));
 error(xos_plot(96+5, area->clip.x1, area->clip.y1));
 line=0;
 sr=search_resblock;
 while((line<startline)&&(sr!=NULL))
 {
  sr=sr->next;
  line++;
 }

 /*for (line=startline; line<endline; line++)
 {*/
 while((line<endline)&&(sr!=NULL))
 {
  wimp_icon dcon;
  dcon.extent.x0=icpos(0); dcon.extent.y0=-(((line+1)*50)+250);
  dcon.extent.x1=icpos(1); dcon.extent.y1=dcon.extent.y0+50;
  dcon.flags=wimp_ICON_TEXT|wimp_ICON_RJUSTIFIED|wimp_ICON_INDIRECTED|
              (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT)|
              (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT);
  dcon.data.indirected_text.text=sr->filename;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(sr->filename);
  error(xwimp_plot_icon(&dcon));
  dcon.extent.x0=icpos(1); dcon.extent.x1=icpos(2);
  dcon.data.indirected_text.text=sr->user;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(sr->user);
  error(xwimp_plot_icon(&dcon));
  sprintf(numconv, "%.2fMb\n",(double)sr->size/(1024*1024));
  dcon.extent.x0=icpos(2); dcon.extent.x1=icpos(3);
  dcon.data.indirected_text.text=numconv;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(numconv);
  error(xwimp_plot_icon(&dcon));
  sprintf(numconv, "%d\n", sr->bitrate);
  dcon.extent.x0=icpos(3); dcon.extent.x1=icpos(4);
  dcon.data.indirected_text.text=numconv;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(numconv);
  error(xwimp_plot_icon(&dcon));
  sprintf(numconv, "%d\n", sr->frequency);
  dcon.extent.x0=icpos(4); dcon.extent.x1=icpos(5);
  dcon.data.indirected_text.text=numconv;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(numconv);
  error(xwimp_plot_icon(&dcon));
  sprintf(token, "CON%d", sr->speed);
  error(xmessagetrans_lookup(&mess_controlblock, token, buffer, 100,
                            NULL, NULL, NULL, NULL, &out, NULL));
  dcon.extent.x0=icpos(5); dcon.extent.x1=icpos(6);
  dcon.data.indirected_text.text=out;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(out);
  error(xwimp_plot_icon(&dcon));
  sprintf(numconv, "%d:%.2d", sr->number/60, sr->number%60);                      dcon.extent.x0=icpos(6);
  dcon.extent.x1=icpos(7);
  dcon.data.indirected_text.text=numconv;
  dcon.data.indirected_text.validation=blank;
  dcon.data.indirected_text.size=strlen(numconv);
  error(xwimp_plot_icon(&dcon));
  line++;
  sr=sr->next;
 }
 error(xwimp_get_rectangle(area, &more));
 if (more) search_drawblock(area, more, xorigin, yorigin);
}

void search_redrawwin(wimp_block * block)
{
 wimp_draw area;
 wimp_window_state wind;
 int xorigin, yorigin;
 int more=0;
 wind.w=block->redraw.w;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll-250;
 area = block->redraw;
 error(xwimp_redraw_window(&area, &more));
 if (more) search_drawblock(&area, more, xorigin, yorigin);
}

char * search_trim(char * in, int len)
{
 if (strlen(in)>len)
 {
  return(in+(strlen(in)-len));
 }
 return (in);
}

void search_click(wimp_block * block)
{
 wimp_window_state wind;
 int xorigin, yorigin, search_no;
 wind.w=win_searchres;
 error(xwimp_get_window_state(&wind));
 xorigin=wind.visible.x0-wind.xscroll;
 yorigin=wind.visible.y1-wind.yscroll-250;
 search_no=((block->pointer.pos.y-yorigin)/-50);
 if ((search_no<0)||(search_no>=search_numres)) return;
 menu_search_lastres=search_no;
 error(xwimp_create_menu(menu_search,
                         block->pointer.pos.x-64,
                         block->pointer.pos.y));
 menu_open=menu_search;
}

void search_browse(int search_no)
{
 int r=0;

 search_result * sr;
 sr=search_resblock;
 while((r<search_no)&&(sr!=NULL))
 {
  sr=sr->next;
  r++;
 }
 if (sr==NULL) return;
 browsed_user.speed=sr->speed;
 browsed_user.ip=sr->ip;
 search_changetype(browse);
 search_new();
 napster_send(sr->user, 211, strlen(sr->user));
 error(xwimp_set_icon_state(win_search, SEARCHWIN_OK,
                   wimp_ICON_SHADED, wimp_ICON_SHADED));
}

void search_complete(mp3file * file)
{
 char out[300];
 search_changetype(complete);
 search_new();
 sprintf(out, "%s %d", file->checksum, file->fullsize);
 /*os_writec('\x4');
 printf("%s\n", out);*/
 napster_send(out, 215, strlen(out));
}

void search_downloadclick(int search_no)
{
 wimp_open getopen;
 wimp_icon_state temp;
 wimp_pointer p;
 int resno;
 int dl_slot=0;
 search_result * sr;
 while((dl_slot<=C_DOWNLOADS)&&(downloads[dl_slot].active!=freesl)) dl_slot++;
 if (dl_slot>=C_DOWNLOADS)
 {
  ui_messalert("ERRMAXD");
  return;
 }
 error(xwimp_get_pointer_info(&p));
 downloads[dl_slot].size=0;
 downloads[dl_slot].totalsize=1;
 search_updatebar(dl_slot);


 sr=search_resblock;
 resno=0;
 while((resno<search_no)&&(sr!=NULL))
 {
  sr=sr->next;
  resno++;
 }

 getopen.w=(wimp_w) downloads[dl_slot].whandle;
 getopen.visible.y1=p.pos.y+96;
 getopen.visible.y0=getopen.visible.y1+win_getb[0]->extent.y0;
 getopen.visible.x0=p.pos.x;
 getopen.visible.x1=p.pos.x+win_getb[0]->extent.x1;
 getopen.xscroll=0; getopen.yscroll=0;
 getopen.next=wimp_TOP;
 error(xwimp_open_window(&getopen));
 temp.w=(wimp_w) downloads[dl_slot].whandle;
 temp.i=GETWIN_FILE;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text,
                    search_trim(sr->filename, 40));
 error(xwimp_set_icon_state((wimp_w)downloads[dl_slot].whandle,
                                                         GETWIN_FILE, 0,0));
 temp.w=(wimp_w) downloads[dl_slot].whandle;
 temp.i=GETWIN_USER;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text,
                    search_trim(sr->user, 20));
 error(xwimp_set_icon_state((wimp_w)downloads[dl_slot].whandle,
                                                          GETWIN_USER, 0,0));
 downloads[dl_slot].searchres=sr;
 strcpy(downloads[dl_slot].filename, sr->filename);
 strcpy(downloads[dl_slot].user, sr->user);
 strcpy(downloads[dl_slot].checksum, sr->id);
 downloads[dl_slot].active=window;
 downloads[dl_slot].filehandle=NULL;
}

void search_changetype(search_type new)
{
 wimp_menu_entry * ent;
 ent = (wimp_menu_entry *) &menu_search->entries;
 search_current_type=new;
 switch(search_current_type)
 {
  case none:
  search_ungrey();
  (ent+1)->icon_flags=0x7000021;
  break;
  default:
  error(xwimp_set_icon_state(win_search, SEARCHWIN_OK,
                   wimp_ICON_SHADED, wimp_ICON_SHADED));
  (ent+1)->icon_flags=0x7000021|wimp_ICON_SHADED;
  break;
 }
 /*
 if(menu_open==menu_search)
 {
  error(xwimp_create_menu(menu_open, 0, 0));
 }*/
}

void search_updatebar(int tno)
{
 float percent=0;
 char pctxt[20]="";
 char buffer[30];
 char * out;
 wimp_icon_state temp;
 switch(downloads[tno].active)
 {
  case freesl: break;
  case window:
  error(xmessagetrans_lookup(&mess_controlblock, "STAT0", buffer, 30,
                                   NULL, NULL, NULL, NULL, &out, NULL));
  strcpy(pctxt, out);
  break;

  case getinfo:
  error(xmessagetrans_lookup(&mess_controlblock, "STAT1", buffer, 30,
                                   NULL, NULL, NULL, NULL, &out, NULL));
  strcpy(pctxt, out);
  break;

  case tc:
  error(xmessagetrans_lookup(&mess_controlblock, "STAT2", buffer, 30,
                                   NULL, NULL, NULL, NULL, &out, NULL));
  strcpy(pctxt, out);
  break;

  case get_one:
  error(xmessagetrans_lookup(&mess_controlblock, "STAT3", buffer, 30,
                                   NULL, NULL, NULL, NULL, &out, NULL));
  strcpy(pctxt, out);
  break;

  case get_header:
  error(xmessagetrans_lookup(&mess_controlblock, "STAT4", buffer, 30,
                                   NULL, NULL, NULL, NULL, &out, NULL));
  strcpy(pctxt, out);
  break;

  case download:
  if(downloads[tno].totalsize!=0)
  {
   percent=((float)100*(float)
              ((float)downloads[tno].size/(float)downloads[tno].totalsize));
   sprintf(pctxt, "%.1f %%", percent);
  }
  break;
 }
 temp.w=(wimp_w) downloads[tno].whandle;
 temp.i=GETWIN_PROGN;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text, pctxt);
 error(xwimp_set_icon_state((wimp_w) downloads[tno].whandle,
                                                  GETWIN_PROGN, 0,0));
 temp.i=GETWIN_BAR;
 error(xwimp_get_icon_state(&temp));
 error(xwimp_resize_icon((wimp_w) downloads[tno].whandle, GETWIN_BAR,
       temp.icon.extent.x0, temp.icon.extent.y0,
       temp.icon.extent.x0+(4*(int)percent), temp.icon.extent.y1));
 error(xwimp_set_icon_state((wimp_w) downloads[tno].whandle,
                                                  GETWIN_BAR, 0, 0));
}

void search_getok(int tno)
{
 if (connected==loggedin)
 {
  downloads[tno].active=getinfo;
  search_updatebar(tno);
  napster_mo_dlrequest(downloads[tno].searchres);
 }
 else
 {
  ui_messalert("ERRNPNC");
 }
}

void get_init(void)
{
 int i;
 for (i=0; i<C_DOWNLOADS; i++) downloads[i].active=freesl;
 for (i=0; i<C_INCOMING; i++) incon[i].active=0;
}

void strcpy_nl(char * target, char * source)
{
 int pos=0;
 while(source[pos]!=0x0d)
 {
  target[pos]=source[pos];
  pos++;
 }
 target[pos]='\0';
}

void get_closewin(int tno)
{
 error(xwimp_close_window((wimp_w) downloads[tno].whandle));
}

void ui_storedetails(void)
{
 FILE * cfile;
 if(error(xosfile_create_dir("<Choices$Write>.Riscster",0))) return;
 cfile=fopen("<Choices$Write>.Riscster.user", "w");
 if (cfile==NULL) return;
 fprintf(cfile, "%s %s %d", username, password, connection);
 fclose(cfile);
}

void ui_loaddetails(void)
{
 FILE * cfile;
 cfile=fopen("Choices:Riscster.user", "r");
 if (cfile==NULL) return;
 fscanf(cfile, "%s %s %d", username, password, &connection);
 fclose(cfile);
}

void message_send(int search_no)
{
 int r=0;
 int x, y;
 wimp_open open;
 wimp_pointer pointer;
 wimp_icon_state temp;
 search_result * sr;
 sr=search_resblock;
 while((r<search_no)&&(sr!=NULL))
 {
  sr=sr->next;
  r++;
 }
 if (sr==NULL) return;
 strcpy(message_user, sr->user);
 temp.w=win_sendmessage;
 temp.i=MESSWIN_USER;
 error(xwimp_get_icon_state(&temp));
 strcpy(temp.icon.data.indirected_text.text,
                    search_trim(sr->user, 20));
 error(xwimp_set_icon_state(win_sendmessage, MESSWIN_USER, 0, 0));
 error(xwimp_get_pointer_info(&pointer));
 open.w=win_sendmessage;
 open.xscroll=0; open.yscroll=0;
 x=pointer.pos.x-64;
 y=pointer.pos.y+64;
 open.visible.x0=x;
 open.visible.x1=x+500;
 open.visible.y0=y;
 open.visible.y1=y+380;
 open.next=wimp_TOP;
 error(xwimp_open_window(&open));
}

void message_sendmessage(void)
{
 char out[255];
 char message[255];
 wimp_icon_state temp;
 temp.w=win_sendmessage;
 temp.i=MESSWIN_MESS;
 error(xwimp_get_icon_state(&temp));
 strcpy_nl(message, temp.icon.data.indirected_text.text);
 sprintf(out, "%s %s", message_user, message);
 napster_send(out, 205, strlen(out));
 error(xwimp_close_window(win_sendmessage));
}

void ui_search_drag(wimp_block * block)
{
 // user has clicked on an icon at the top of the search window
 wimp_drag drag;
 wimp_window_state wind;
 wind.w=win_search;

 topdrag_stat=(block->pointer.i-SEARCH_HEADOFFSET+1);
 topdrag_startx=block->pointer.pos.x;

 error(xwimp_get_window_state(&wind));
 drag.w=win_search;
 drag.type=wimp_DRAG_USER_POINT,
 drag.initial.x0=block->pointer.pos.x;
 drag.initial.x1=block->pointer.pos.x;
 drag.initial.y0=block->pointer.pos.y;
 drag.initial.y1=block->pointer.pos.y;
 drag.bbox=wind.visible;
 drag.bbox.y0=block->pointer.pos.y;
 drag.bbox.y1=drag.bbox.y0;
 drag.bbox.x0=block->pointer.pos.x-colwidth[topdrag_stat-1];
 drag.handle=NULL;
 drag.draw=NULL;
 drag.undraw=NULL;
 drag.redraw=NULL;
 error(xwimp_drag_box(&drag));
}

void mess_dragbox(wimp_block * block)
{
 int col;
 int disp;
 wimp_pointer pinfo;

 if (topdrag_stat)
 {
  error(xwimp_get_pointer_info(&pinfo));
  disp=pinfo.pos.x-topdrag_startx;

  colwidth[topdrag_stat-1]+=disp;
  if(colwidth[topdrag_stat-1]<MINCOL) colwidth[topdrag_stat-1]=MINCOL;
  if (disp)
  {
   // only bother with this is we haven't already done it
   resize_searchhead(topdrag_stat-1);
   ui_force_topdraw(disp, topdrag_stat-1);
  }
  resize_searchwin();
  search_update_wholewin();
  topdrag_startx=pinfo.pos.x;

  topdrag_stat=0;
 }
}

void ui_force_topdraw(int dist, int start)
{
 wimp_window_state wind;
 wind.w=win_search;
 error(xwimp_get_window_state(&wind));
 error(xwimp_force_redraw(win_search,
                          icpos(start), -232,
                          icpos(7)-((dist<0)?dist:0),
                          -180));
}

int icpos(int i)
{
 int j, sum=0;
 for (j=0; j<i; j++)
 {
  sum+=colwidth[j];
 }
 return(sum);
}

void resize_searchhead(int start)
{
 int i;
 for (i=start; i<7; i++)
 {
  error(xwimp_resize_icon(win_search,
                          SEARCH_HEADOFFSET+i,
                          icpos(i), -232, icpos(i+1), -180));
 }
}

void resize_searchwin(void)
{
 os_box ext;
 int newxmax;
 newxmax = (DEF_SRCHSIZE<icpos(7))?
           icpos(7) : DEF_SRCHSIZE;

 ext.x0=win_searchresb->extent.x0;
 ext.x1=win_searchresb->extent.x0+newxmax;
 win_searchresb->extent.x1=ext.x1;
 ext.y0=win_searchresb->extent.y0;
 ext.y1=win_searchresb->extent.y1;
 error(xwimp_set_extent(win_searchres, &ext));
 ext.x0=win_searchb->extent.x0;
 ext.x1=win_searchb->extent.x0+newxmax;
 win_searchb->extent.x1=ext.x1;
 ext.y0=win_searchb->extent.y0;
 ext.y1=win_searchb->extent.y1;
 error(xwimp_set_extent(win_search, &ext));
}





